﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class SineBase : MonoBehaviour
{


    public enum Wave
    {
        sine,
        triangle,
        sawtooth,
        reverseSawtooth,
        square
    }

    public Wave wave = Wave.sine;

    [Header("====== 生命周期 ======")]
    public float period = 4;
    public float periodRandom = 0;
    public float periodOffset = 0;
    public float periodOffsetRandom = 0;
    [Header("====== 偏差值 ======")]
    [SerializeField]
    private float _magnitude = 1.0f;

    public float magnitude
    {
        get
        {
            return _magnitude;
        }
        set
        {
            _magnitude = value;
            this.mag = _magnitude;
            this.mag += Random.Range(0f, 1.0f) * this.magnitudeRandom;
        }
    }
    public float magnitudeRandom = 0;

    [Header("====== 运行时 ======")]
    public float value;
    protected float i;
    [SerializeField]
    protected float mag;
    protected float initialValue;
    protected float initialValue2;
    protected float lastKnownValue;
    protected float lastKnownValue2;

    const float _2pi = Mathf.PI * 2;
    const float _pi_2 = Mathf.PI / 2;
    const float _3pi_2 = Mathf.PI * 3 / 2;

    private void Awake()
    {
        this.Init();
    }

    public void Init()
    {
        if (this.period == 0)
        {
            this.i = 0;
        }
        else
        {
            this.i = (this.periodOffset / this.period) * Mathf.PI * 2;
            this.i += ((Random.Range(0, 1.0f) * this.periodOffsetRandom) / this.period) * Mathf.PI * 2;
        }

        this.mag = this.magnitude;
        this.mag += Random.Range(0, 1.0f) * this.magnitudeRandom;

        this.initialValue = 0;
        this.initialValue2 = 0;

        //记录初始值状态
        AfterInit();
    }

    /// <summary>
    /// 实现此方法来获得初始的值
    /// </summary>
    abstract protected void AfterInit();


    public float GetValue()
    {
        return value;
    }

    public void setPase(float x)
    {
        this.i = (x * Mathf.PI * 2) % (Mathf.PI * 2);
        _UpdateFromPhase();
    }

    private float WaveFunc(float x)
    {
        x = x % _2pi;
        switch (this.wave)
        {
            case Wave.sine:     // sine
                return Mathf.Sin(x);
            case Wave.triangle:     // triangle
                if (x <= _pi_2)
                    return x / _pi_2;
                else if (x <= _3pi_2)
                    return 1 - (2 * (x - _pi_2) / Mathf.PI);
                else
                    return (x - _3pi_2) / _pi_2 - 1;
            case Wave.sawtooth:     // sawtooth
                return 2 * x / _2pi - 1;
            case Wave.reverseSawtooth:      // reverse sawtooth
                return -2 * x / _2pi + 1;
            case Wave.square:       // square
                return x < Mathf.PI ? -1 : 1;
        };

        // should not reach here
        return 0;
    }


    private void Update()
    {
        var dt = Time.deltaTime;

        if (!this.enabled || dt == 0)
            return;

        if (this.period == 0)
            this.i = 0;
        else
        {
            this.i += (dt / this.period) * _2pi;
            this.i = this.i % _2pi;
        }

        this._UpdateFromPhase();
    }



    private void _UpdateFromPhase()
    {
        var waveRes = WaveFunc(this.i) * this.mag;//wave 函数计算结果
        this.value = waveRes;// 保存到 value 值中
        UpdateFromPhase(this.value);
    }

    /// <summary>
    /// 实现此方法,以便通过sine的值来使得情况发生变化
    /// </summary>
    /// <param name="value"></param>
    abstract protected void UpdateFromPhase(float value);

}
